package com.hh.demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.hh.demo.domain.Course;
import com.hh.demo.domain.CourseMarket;
import com.hh.demo.domain.CourseOrder;
import com.hh.demo.domain.CourseOrderItem;
import com.hh.demo.dto.CourseOrderCreateParamsDto;
import com.hh.demo.dto.PayDto;
import com.hh.demo.exception.GlobalException;
import com.hh.demo.feignClient.CourseUserLearnFeignClient;
import com.hh.demo.mapper.CourseOrderMapper;
import com.hh.demo.result.JSONResult;
import com.hh.demo.service.ICourseOrderItemService;
import com.hh.demo.service.ICourseOrderService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.hh.demo.util.AssertUtil;
import com.hh.demo.util.CodeGenerateUtils;
import com.hh.demo.vo.CourseItemVo;
import com.hh.demo.vo.CourserOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author goeun
 * @since 2022-07-29
 */
@Service
@Slf4j
public class CourseOrderServiceImpl extends ServiceImpl<CourseOrderMapper, CourseOrder> implements ICourseOrderService {
    @Resource
    private RedisTemplate<Object,Object> redisTemplate;
    @Resource
    private CourseUserLearnFeignClient courseUserLearnFeignClient;
    @Resource
    private ICourseOrderItemService courseOrderItemService;
    @Resource
    private RocketMQTemplate rocketMQTemplate;

    @Override
    public String placeOrder(CourseOrderCreateParamsDto dto) {
        Long loginId = 1L;
        String courseIdsStr = StringUtils.join(dto.getCourseIds(), ",");
        String key = courseIdsStr+":"+loginId;
        //校验防重token
        Object tokenTmp = redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(tokenTmp,"没有防重token？请重新下单！");
        AssertUtil.isEquals(dto.getToken(),tokenTmp.toString(),"token错误，请重新下单！");
        //feign查询课程相关的信息
        JSONResult jsonResult = courseUserLearnFeignClient.courseOrderInfo(courseIdsStr);
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程信息有误，请重新下单！");
        String voStr = JSON.toJSONString(jsonResult.getData());
        CourserOrderVo courserOrderVo = JSONObject.parseObject(voStr, CourserOrderVo.class);
        List<CourseItemVo> courseInfos = courserOrderVo.getCourseInfos();
        AssertUtil.isNotNull(courseInfos,"课程信息有误，请重新下单！");

        CourseOrder order = new CourseOrder();
        //保存主订单
        saveOrder(order,dto, loginId);

        //保存子订单
        StringBuilder sb = new StringBuilder();
        sb.append("课程[");
        saveItemOrder(courseInfos, order, sb);
        sb.append("]的订单");

        //在遍历课程相关的数据时，拼接好主订单的标题，
        //修改主订单
        order.setTitle(sb.toString());
        //updateById(order);
        Map<String, Object> extParams = new HashMap<>();
        extParams.put("userId",loginId);
        extParams.put("courseId",courseIdsStr);
        //发送事务消息
        PayDto payDto = new PayDto(order.getTotalAmount(),order.getPayType(),null,order.getOrderNo(),order.getUserId(),JSON.toJSONString(extParams),order.getTitle());
        log.info("开始发送事务消息");
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(payDto)).build();
        TransactionSendResult sendResult = rocketMQTemplate.sendMessageInTransaction(
                "order-producer",
                "course-order-topic:course-order-tag",
                message,//消息对象
                order//额外参数
        );

        log.info("发送事务消息完成，开始检查事务消息状态");
        LocalTransactionState localTransactionState = sendResult.getLocalTransactionState();
        SendStatus sendStatus = sendResult.getSendStatus();
        if (localTransactionState!=LocalTransactionState.COMMIT_MESSAGE||sendStatus!=SendStatus.SEND_OK){
            log.info("事务消息状态异常！");
            throw new GlobalException("事务消息状态异常，下单失败！");
        }


        //发布支付超时延迟消息=================
        try {
            SendResult delayedSendResult = rocketMQTemplate.syncSend(
                    "paytimeout-topic:paytimeout-tag",//topic:tag
                    MessageBuilder.withPayload(order.getOrderNo()).build(),//消息体
                    2000,//发送延迟消息的超时时间
                    4//延迟等级  如果是30分钟 16
            );
            SendStatus delayedStatus = delayedSendResult.getSendStatus();
            if(delayedStatus != SendStatus.SEND_OK){
                 /*
                   先尝试重试3次，如果3次重试都发不出去
                     1.记录一个log表
                     2.发站内信，发短信，发邮件通知运维人员，人工接入操作
             */
            }
        } catch (Exception e) {
            e.printStackTrace();
            //报错，我们需要做补偿机制
            /*
             先尝试重试3次，如果3次重试都发不出去
             1.记录一个log表
             2.发站内信，发短信，发邮件通知运维人员，人工接入操作
             */
        }


        //删除防重token
        redisTemplate.delete(key);
        return order.getOrderNo();
    }

    @Override
    public void payOrder(CourseOrder courseOrder) {
        courseOrder.setStatusOrder(CourseOrder.STATE_PAY_SUCCESS);
        courseOrder.setUpdateTime(new Date());
        updateById(courseOrder);
    }


    @Override
    public void cancelOrder(String orderNo) {
        //应该拿着订单号去支付宝查询一波，看订单是否支付成功  不调用了
        CourseOrder courseOrder = selectOne(new EntityWrapper<CourseOrder>().eq("order_no",orderNo));
        AssertUtil.isNotNull(courseOrder,"订单不存在");
        if(courseOrder.getStatusOrder().intValue() != CourseOrder.STATE_PAY_SUCCESS.intValue()){
            courseOrder.setStatusOrder(CourseOrder.STATE_CANCEL);
            updateById(courseOrder);
        }
        //支付超时取消的时候，如果是秒杀订单，需要还库存
        // @TODO  秒杀还库存----  支付成功删除预创订单
/*        KillPreOrderParamsDto preOrder = (KillPreOrderParamsDto)redisTemplate.opsForValue().get(orderNo);
        if(preOrder != null){
            *//*RSemaphore semaphore = redissonClient.getSemaphore(key);//获取唯一的信号量对象
            Integer killCount = 1;//默认秒杀一个，如果是秒杀多个，前端传递过来
            boolean tryAcquire = semaphore.trySetPermits(1);*//*
        }*/
    }


    private void saveItemOrder(List<CourseItemVo> courseInfos, CourseOrder order, StringBuilder sb) {
        courseInfos.forEach(courseInfoVo->{
            Course course = courseInfoVo.getCourse();
            CourseMarket courseMarket = courseInfoVo.getCourseMarket();
            CourseOrderItem item = new CourseOrderItem();
            //item.setOrderId(order.getId());
            item.setAmount(courseMarket.getPrice());
            item.setCount(1);
            order.setTotalCount(order.getTotalCount() + 1);
            order.setTotalAmount(order.getTotalAmount().add(item.getAmount()));
            sb.append(course.getName()).append(",");
            item.setCreateTime(new Date());
            item.setCourseId(course.getId());
            item.setCourseName(course.getName());
            item.setCoursePic(course.getPic());
            item.setVersion(order.getVersion());
            item.setOrderNo(order.getOrderNo());
            //courseOrderItemService.insert(item);
            order.getItems().add(item);
        });
    }

    private void saveOrder(CourseOrder order,CourseOrderCreateParamsDto dto, Long loginId) {
        order.setCreateTime(new Date());
        order.setOrderNo(CodeGenerateUtils.generateOrderSn(loginId));
        order.setStatusOrder(0);
        order.setUserId(loginId);
        order.setVersion(0);
        order.setPayType(dto.getPayType());
        //insert(order);
    }


}
